home *** CD-ROM | disk | FTP | other *** search
- /*
- * main.c --
- *
- * This file contains the main program for "moat", a windowing
- * shell based on Motif and Tcl. It also provides a template that
- * can be used as the basis for main programs for other Tcl/Motif
- * applications.
- *
- * Copyright 1993 Jan Newmarch, University of Canberra.
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The author
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
-
- *
- * Copyright 1990-1992 Regents of the University of California.
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /usrs/tm/RCS/main.c,v 1.2 1993/07/14 20:01:43 jan Exp jan $";
- #endif
- /*
- #include "tkConfig.h"
- #include "tkInt.h"
- */
- #include "tm.h"
- #include "tmFuncs.h"
- #include <X11/Xos.h>
-
- /*
- * Declarations for library procedures:
- */
-
- extern int isatty();
-
- /*
- * Command used to initialize moat:
- */
-
- char *tcl_RcFileName = NULL;
-
- char *prompt;
-
- /*
- * Global variables used by the main program:
- */
-
- static Widget toplevel;
- static Tcl_Interp *interp; /* Interpreter for this application. */
- static Tcl_DString command; /* Used to assemble lines of terminal input
- * into Tcl commands. */
- static int tty; /* Non-zero means standard input is a
- * terminal-like device. Zero means it's
- * a file. */
- /*
- Tcl_HashTable WidgetTable; */ /* Table to locate info about each widget */
- /*
- * Command-line options:
- */
-
- char *fileName = NULL;
- char *name = NULL;
-
- static XrmOptionDescRec options[] =
- {
- {"-file", "file", XrmoptionSepArg, NULL},
- {"-f", "file", XrmoptionSepArg, NULL}
- };
-
- static XtResource resources[] =
- {
- {XtNfile,
- XtCFile,
- XtRString,
- sizeof(String),
- XtOffset(Tm_ResourceTypePtr, fileName),
- XmRImmediate,
- NULL
- }
- };
-
-
- /*
- * Forward declarations for procedures defined later in this file:
- */
-
- static void StdinProc _ANSI_ARGS_((XtPointer clientData,
- int *fid, XtInputId *id));
-
- /*
- * The following structure defines all of the commands supported by
- * Tm, and the C procedures that execute them.
- */
-
- typedef struct {
- char *name; /* Name of command. */
- int (*cmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
- int argc, char **argv));
- /* Command procedure. */
- } TmCmd;
-
-
- void Tm_Init ()
- {
- register TmCmd *cmdPtr;
- char *libDir;
-
- /*
- * Bind in Tm's commands.
- */
-
- Tm_LoadWidgetCommands (interp);
-
- /*
- * Set variables for the intepreter.
- */
-
- libDir = getenv("TM_LIBRARY");
- if (libDir == NULL) {
- libDir = TM_LIBRARY;
- }
- Tcl_SetVar(interp, "tm_library", libDir, TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp, "tm_version", TM_VERSION, TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp, "tmVersion", TM_VERSION, TCL_GLOBAL_ONLY);
-
- /*
- * Initialize hash table containing info about each widget
- */
- /*
- Tcl_InitHashTable(&WidgetTable, TCL_STRING_KEYS);
- */
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Tcl_AppInit --
- *
- * This procedure performs application-specific initialization.
- * Most applications, especially those that incorporate additional
- * packages, will have their own version of this procedure.
- *
- * Results:
- * Returns a standard Tcl completion code, and leaves an error
- * message in interp->result if an error occurs.
- *
- * Side effects:
- * Depends on the startup script.
- *
- *----------------------------------------------------------------------
- */
-
- int
- Tcl_AppInit(interp)
- Tcl_Interp *interp;
- {
- /*
- * Call the init procedures for included packages. Each call should
- * look like this:
- *
- * if (Mod_Init(interp) == TCL_ERROR) {
- * return TCL_ERROR;
- * }
- *
- * where "Mod" is the name of the module.
- */
-
- /*
- * Call Tcl_CreateCommand for application-specific commands, if
- * they weren't already created by the init procedures called above.
- */
-
- /*
- * Specify a user-specific startup file to invoke if the application
- * is run interactively. Typically the startup file is "~/.apprc"
- * where "app" is the name of the application. If this line is deleted
- * then no user-specific startup file will be run under any conditions.
- */
-
- tcl_RcFileName = "~/.moatrc";
- return TCL_OK;
- }
-
-
- /*
- *----------------------------------------------------------------------
- * Tm_Class -
- * The tcl source filename is used to construct the class name as
- * follows: a leading 'x' is capitalised and so is the following
- * character, else the leading char is capitalised
- *
- * Result
- * the class name as a new string
- *
- * Side effects
- * None
- *----------------------------------------------------------------------
- */
-
- char *
- Tm_Class(argc, argv)
- int argc;
- char **argv;
- {
- char *path;
- char *class;
- int n;
-
- path = argv[0];
- for (n = 1; n < argc - 1; n++) {
- if (strcmp(argv[n], "-f") == 0 ||
- strcmp(argv[n], "-file") == 0)
- path = argv[n+1];
- }
-
- class = strrchr(path, '/');
- if (class == NULL)
- class = path;
- else class++;
-
- class = XtNewString(class);
- if (class[0] == 'x') {
- class[0] = 'X';
- class[1] = toupper(class[1]);
- } else
- class[0] = toupper(class[0]);
-
- return class;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * main --
- *
- * Main program for moat.
- *
- * Results:
- * None. This procedure never returns (it exits the process when
- * it's done
- *
- * Side effects:
- * This procedure initializes the moat world and then starts
- * interpreting commands; almost anything could happen, depending
- * on the script being interpreted.
- *
- *----------------------------------------------------------------------
- */
-
- int
- main(argc, argv)
- int argc; /* Number of arguments. */
- char **argv; /* Array of argument strings. */
- {
- char *args, *p, *msg;
- char *class;
- char buf[20];
- int result;
- int code;
- XtAppContext appContext;
- Tm_ResourceType main_resources;
- Tm_Widget *wPtr;
- static Tm_Display displayInfo;
- XtActionsRec action;
-
- action.string = "exec";
- action.proc = Tm_ActionsHandler;
-
- interp = Tcl_CreateInterp();
- #ifdef TCL_MEM_DEBUG
- Tcl_InitMemory(interp);
- #endif
-
- Tm_Init ();
- class = Tm_Class(argc, argv);
-
- toplevel = XtAppInitialize (&appContext, class, options, XtNumber(options),
- (unsigned int *) &argc, argv, NULL, NULL, 0);
-
- XtAppAddActions(appContext, &action, 1);
-
- displayInfo.commWidget = NULL;
- displayInfo.toplevel = toplevel;
- displayInfo.display = XtDisplay(toplevel);
-
- wPtr = (Tm_Widget *) ckalloc (sizeof (Tm_Widget));
- wPtr -> interp = interp;
- wPtr -> widget = toplevel;
- wPtr -> pathName = XtNewString(".");
- wPtr -> parent = "."; /* kludge to stop later breakages */
- wPtr -> displayInfo = &displayInfo;
-
- Tm_StoreWidgetInfo(".", wPtr, interp);
-
- Tcl_CreateCommand (interp, ".", Tm_AnyWidgetCmd,
- (ClientData) wPtr, (void (*) ()) NULL);
-
- XtAddCallback(toplevel, XmNdestroyCallback, Tm_DestroyWidgetHandler,
- (XtPointer) wPtr);
-
- Tm_RegisterConverters(interp, appContext);
-
- /*
- * Parse command-line arguments.
- */
- XtGetApplicationResources(toplevel,
- (XtPointer) &main_resources,
- resources,
- XtNumber(resources),
- NULL,
- 0);
- fileName = main_resources.fileName;
-
- if (name == NULL) {
- if (fileName != NULL) {
- p = fileName;
- } else {
- p = argv[0];
- }
- name = strrchr(p, '/');
- if (name != NULL) {
- name++;
- } else {
- name = p;
- }
- prompt = name;
- } else {
- prompt = name;
- }
-
- /*
- * Register the interpreter for the send command
- */
- Tm_RegisterInterp(interp, name, &displayInfo);
-
- /*
- * Initialize the Tm application and arrange to map the main window
- * after the startup script has been executed, if any. This way
- * the script can withdraw the window so it isn't ever mapped
- * at all.
- */
-
-
- /*
- * Make command-line arguments available in the Tcl variables "argc"
- * and "argv".
- */
-
- args = Tcl_Merge(argc-1, argv+1);
- Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
- ckfree(args);
- sprintf(buf, "%d", argc-1);
- Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY);
-
- /*
- * Invoke application-specific initialization.
- */
-
- /*
- if (Tcl_AppInit(interp) != TCL_OK) {
- fprintf(stderr, "Tcl_AppInit failed: %s\n", interp->result);
- }
- */
-
- /*
- * Execute moat's initialization script, followed by the script specified
- * on the command line, if any.
- */
-
- tty = isatty(0);
- if (fileName != NULL) {
- result = Tcl_VarEval(interp, "source ", fileName, (char *) NULL);
- if (result != TCL_OK) {
- goto error;
- }
- /* make imoat also read from stdin - JN */
- { char *p;
-
- p = strrchr(argv[0], '/');
- if (p != NULL) {
- p++;
- } else {
- p = argv[0];
- }
-
- if (strcmp (p, "imoat") == 0) {
- XtAppAddInput(appContext, 0, (XtPointer) XtInputReadMask,
- StdinProc, NULL);
- fprintf(stderr, "%s: ", prompt); /* changed from stdout - JN */
- fflush(stderr);
- } else {
- tty = 0;
- }
- }
- } else {
- /*
- * Commands will come from standard input. Set up a handler
- * to receive those characters and print a prompt if the input
- * device is a terminal.
- */
-
- if (tcl_RcFileName != NULL) {
- Tcl_DString buffer;
- char *fullName;
-
- fullName = Tcl_TildeSubst(interp, tcl_RcFileName, &buffer);
- if (fullName == NULL) {
- fprintf(stderr, "%s\n", interp->result);
- } else {
- if (access(fullName, R_OK) == 0) {
- code = Tcl_EvalFile(interp, fullName);
- if (code != TCL_OK) {
- fprintf(stderr, "%s\n", interp->result);
- }
- }
- }
- Tcl_DStringFree(&buffer);
- }
-
- XtAppAddInput(appContext, 0, (XtPointer) XtInputReadMask,
- StdinProc, NULL);
-
- if (tty) {
- fprintf(stderr, "%s: ", prompt); /* changed from stdout - JN */
- fflush(stderr);
- }
- }
- fflush(stdout);
- Tcl_DStringInit(&command);
- (void) Tcl_Eval(interp, "update");
-
- /*
- * Loop infinitely, waiting for commands to execute. When there
- * are no windows left, Tm_MainLoop returns and we clean up and
- * exit.
- */
-
- XtRealizeWidget (toplevel);
-
- XtAppMainLoop (appContext);
-
- error:
- msg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
- if (msg == NULL) {
- msg = interp->result;
- }
- fprintf(stderr, "%s\n", msg);
- Tcl_Eval(interp, "destroy .");
- exit(1);
- #ifndef sgi
- return 0; /* Needed only to prevent compiler warnings. */
- #endif
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * StdinProc --
- *
- * This procedure is invoked by the event dispatcher whenever
- * standard input becomes readable. It grabs the next line of
- * input characters, adds them to a command being assembled, and
- * executes the command if it's complete.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Could be almost arbitrary, depending on the command that's
- * typed.
- *
- *----------------------------------------------------------------------
- */
-
- /* ARGSUSED */
- static void
- StdinProc(clientData, fid, id)
- XtPointer clientData; /* Not used. */
- int *fid;
- XtInputId *id;
- {
- #define BUFFER_SIZE 4000
- char input[BUFFER_SIZE+1];
- static int gotPartial = 0;
- char *cmd;
- int result, count;
-
- count = read(fileno(stdin), input, BUFFER_SIZE);
- if (count <= 0) {
- if (!gotPartial) {
- if (tty) {
- Tcl_Eval(interp, "destroy .");
- exit(0);
- } else {
- XtRemoveInput(*id);
- }
- return;
- } else {
- count = 0;
- }
- }
- cmd = Tcl_DStringAppend(&command, input, count);
- if (count != 0) {
- if ((input[count-1] != '\n') && (input[count-1] != ';')) {
- gotPartial = 1;
- }
- if (!Tcl_CommandComplete(cmd)) {
- gotPartial = 1;
- }
- }
- gotPartial = 0;
- result = Tcl_RecordAndEval(interp, cmd, 0);
- Tcl_DStringFree(&command);
- if (*interp->result != 0) {
- if ((result != TCL_OK) || (tty)) {
- printf("%s\n", interp->result);
- }
- }
- if (tty) {
- fprintf(stderr, "%s: ", prompt); /* changed from stdout - JN */
- fflush(stderr);
- }
- }
-
-